Threading


Threading is the term for running two or more parts of your program simultaneously. Salsa makes this as easy as typing one word, and provides tools to control the execution of your program.

A thread is a complete program. That is, a thread contains all the information of variables, function calls, and executing commands. Two threads cannot "talk" to each other, because each is a totally encapsulated program. However, they are powerful because since they can run concurrently, you can increase preformance, and give the user a better interface. For example, while you are waiting for user input, you could be doing other miscellaneous tasks. To illustrate threads, consider the following program which finds the minimum and maximum value of a list and prints the results:
def min(list)
{
	x = 9999;
	for(k in list)
		if (k < x) x = k;
	return x;
}

def max(list)
{
        x = -9999;
        for(k in list)
                if (k > x) x = k;
        return x;
}

def PrintMin(list) { println("The min of ",list," is ",min(list)); }
def PrintMax(list) { println("The max of ",list," is ",max(list)); }

def main()
{
	list = [4,2,5,3,1];
	PrintMin(list);
	PrintMax(list);
}

This will print 1 and 5 on the screen. Now, in this case, it would be nice if both PrintMin and PrintMax ran simultaneously. To do this, you have to tell Salsa to create a new thread, and call a function within that thread. To do this, put the word "thread" before the function name. Therefore, the last 2 lines of main should be "thread PrintMin(list);" and "thread PrintMax(list);" After main ends, its thread is deleted. However, since the two new threads are still running, the program will continue. Only when the last thread ends will the program finish. Note that any function can be threaded without any change to its definition. Also, you cannot get the return value of a threaded function, since it will return immediatly and run concurrently. Actually, the return value of the threaded function can be used to control its execution as described later in this section.

Most computers cannot actually multi-thread. In these cases, Salsa must emulate the multi-threading. On these computers, your program will run just as fast as if you had left out the "thread" word. However, on machines which can support it, your programs will run much faster. Also, as in the case of doing something while waiting for user input, the threading is helpful even on serial computers. Another advantage of threading even on a serial computer comes with the thread control described next.

Sometimes you will want some degree of control over the execution of the threads. For example, let's say you have one thread which is printing messages periodically, and at the same time, in another thread, you want to interact with the user. At this point, you will want to temporarily stop the printing thread so that messages aren't displayed while the user is attempting to type, and then resume its execution after the user interaction is over. There are several functions which let you control threads.

One technique is called preempting. This is when one thread takes total control, and doesn't let any other thread execute. You can specify lines of code which should be preemptive by typing the word "preempt" and following it with the statement (or block) which should be executed preemptivly.

Sometimes, however, you want control over one particular thread. To do this, you need that thread's unique indentifying code. This is returned by any function which is threaded. Therefore, "ThreadID = thread SomeFunction()" threads SomeFunction and puts the thread ID into ThreadID. Then you can use member functions as described in Lists II to control its behavior. Calling Suspend() suspends the thread, which means it stops executing code from that thread. To resume executing that thread, call Resume(). If the only threads left are suspended (probobaly some code suspended the thread but "forgot" to resume it) the whole program terminates, since there is no way to resume those threads, and there is no active code to execute. To abort a thread, you could just suspend it and never resume, but using the Abort() function is better because it can recycle the memory used by the thread. If a thread finishes, you will still have a reference to it. Nothing bad can happen if you suspend, resume, or do anything else to a finished thread. However, if you need to know if a thread is competed, you can call the IsDone() member function which returns 1 if it is done, 0 if it isn't.

One thing you may want to do is to create a thread, do some things, and then wait for that thread to finish before continuing. For the wait, you could write code like this (assuming the thread id is in ThreadID):
while (!ThreadID.IsDone()) ;

However, a better way is to use the ResumeAfter() member function which causes the current thread to be suspended, but resumed after the other thread finishes. This is better not only because is it less code, but it makes your entire program run faster.
Web page maintained by Jason Cohen